package com.koi.system.controller.menu;

import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.koi.common.anno.KoiLog;
import com.koi.common.anno.KoiMenuDataScope;
import com.koi.common.constants.KoiConstants;
import com.koi.common.enums.log.OperType;
import com.koi.common.ex.koi.YUtil;
import com.koi.common.satoken.KoiLoginUtil;
import com.koi.model.bo.element.CascaderLongBo;
import com.koi.model.bo.system.SysMenuBo;
import com.koi.model.vo.base.BaseVo;
import com.koi.model.vo.system.SysMenuVo;
import com.koi.pojo.system.SysMenu;
import com.koi.system.service.menu.SysMenuService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author ･ᴗ･
 * @description [菜单权限表-控制层]
 */
@Validated
@RequestMapping("/koi")
@RequiredArgsConstructor
@RestController
public class SysMenuController {

    private final SysMenuService sysMenuService;

    /**
     * @description [分页查询]
     * @author ･ᴗ･
     */
    @SaCheckPermission("system:menu:list")
    @GetMapping("/sysMenu/listPage")
    public IPage<SysMenu> listPage(SysMenuVo vo) {
        // 分页构造器
        Page<SysMenu> page = new Page<>(vo.getPageNo(), vo.getPageSize());
        // 条件构造器
        LambdaQueryWrapper<SysMenu> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(StringUtils.isNotBlank(vo.getMenuName()), SysMenu::getMenuName, vo.getMenuName());
        wrapper.eq(StringUtils.isNotBlank(vo.getMenuStatus()), SysMenu::getMenuStatus, vo.getMenuStatus());
        wrapper.like(StringUtils.isNotBlank(vo.getAuth()), SysMenu::getAuth, vo.getAuth());
        // 进行分页查询
        page = sysMenuService.page(page, wrapper);
        return page;
    }

    /**
     * @description [查询菜单]
     * @author ･ᴗ･
     */
    @KoiMenuDataScope(menuAlias = "t1")
    @GetMapping("/sysMenu/list")
    public List<SysMenu> list(SysMenuVo vo) {
        // 条件构造器
        LambdaQueryWrapper<SysMenu> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(StringUtils.isNotBlank(vo.getMenuName()), SysMenu::getMenuName, vo.getMenuName());
        wrapper.eq(StringUtils.isNotBlank(vo.getMenuStatus()), SysMenu::getMenuStatus, vo.getMenuStatus());
        wrapper.like(StringUtils.isNotBlank(vo.getAuth()), SysMenu::getAuth, vo.getAuth());
        wrapper.orderByAsc(SysMenu::getSorted);
        return sysMenuService.listSysMenu(vo);
    }

    /**
     * @description [查询一个]
     * @author ･ᴗ･
     */
    @GetMapping("/sysMenu/getById/{id}")
    public SysMenu getById(@PathVariable Long id) {
        return sysMenuService.getById(id);
    }

    /**
     * @description [新增]
     * @author ･ᴗ･
     */
    @KoiLog(title = "新增菜单", operType = OperType.ADD)
    @SaCheckPermission("system:menu:add")
    @PostMapping("/sysMenu/add")
    public void add(@Validated @RequestBody SysMenu sysMenu) {
        // 路由Path不能重复
        if (StringUtils.isNotBlank(sysMenu.getPath())) {
            // 条件构造器
            LambdaQueryWrapper<SysMenu> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(SysMenu::getPath, sysMenu.getPath());
            long count = sysMenuService.count(wrapper);
            YUtil.isTrue(count > 1L, "请联系管理员，检查路由path重复多次");
            if (count == 1L) {
                SysMenu menu = sysMenuService.getOne(wrapper);
                YUtil.isTrue(!Objects.equals(menu.getMenuId(), sysMenu.getMenuId()), "该路由path已存在");
            }
        }
        // 如果是按钮类型并且非外链，必须得隐藏。
        if (sysMenu.getMenuType().equals("3") && StringUtils.isBlank(sysMenu.getIsLink())) {
            sysMenu.setIsHide(KoiConstants.ZERO_STRING);
        }
        if (StringUtils.isNotBlank(KoiLoginUtil.getUserName())) {
            sysMenu.setCreateBy(KoiLoginUtil.getUserName());
        }
        YUtil.isTrue(!sysMenuService.save(sysMenu), "新增失败，请稍后重试");
    }

    /**
     * @description [修改]
     * @author ･ᴗ･
     */
    @KoiLog(title = "修改菜单", operType = OperType.UPDATE)
    @SaCheckPermission("system:menu:update")
    @PostMapping("/sysMenu/update")
    public void update(@Validated @RequestBody SysMenu sysMenu) {
        // 路由Path不能重复
        if (StringUtils.isNotBlank(sysMenu.getPath())) {
            // 条件构造器
            LambdaQueryWrapper<SysMenu> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(SysMenu::getPath, sysMenu.getPath());
            long count = sysMenuService.count(wrapper);
            YUtil.isTrue(count > 1L, "请联系管理员，检查路由path重复多次");
            if (count == 1L) {
                SysMenu menu = sysMenuService.getOne(wrapper);
                YUtil.isTrue(!Objects.equals(menu.getMenuId(), sysMenu.getMenuId()), "该路由path已存在");
            }
        }
        if (StringUtils.isNotBlank(KoiLoginUtil.getUserName())) {
            sysMenu.setUpdateBy(KoiLoginUtil.getUserName());
        }
        YUtil.isTrue(!sysMenuService.updateById(sysMenu), "修改失败，请稍后重试");
    }

    /**
     * @description [删除]
     * @author ･ᴗ･
     */
    @KoiLog(title = "删除菜单", operType = OperType.DELETE)
    @SaCheckPermission("system:menu:delete")
    @PostMapping("/sysMenu/deleteById/{id}")
    public void delete(@PathVariable Long id) {
        SysMenu menu = sysMenuService.getById(id);
        YUtil.isTrue(ObjectUtils.isEmpty(menu) || menu.getMenuId() == null, "请选择需要删除的数据");
        // 条件构造器
        LambdaQueryWrapper<SysMenu> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysMenu::getParentId, menu.getMenuId());
        long count = sysMenuService.count(wrapper);
        YUtil.isTrue(count > 0L, "请先删除该节点下的子节点");
        YUtil.isTrue(!sysMenuService.removeById(id), "删除失败，请稍后重试");
    }

    /**
     * @description [批量删除]
     * @author ･ᴗ･
     */
    @KoiLog(title = "批量删除菜单", operType = OperType.DELETE)
    @SaCheckPermission("system:menu:delete")
    @PostMapping("/sysMenu/batchDelete")
    public void batchDelete(@RequestBody List<Long> ids) {
        YUtil.isTrue(!sysMenuService.removeBatchByIds(ids), "删除失败，请稍后重试");
    }


    /**
     * @description [修改状态]
     * @author ･ᴗ･
     */
    @SaCheckPermission("system:menu:update")
    @PostMapping("/sysMenu/updateStatus/{id}/{menuStatus}")
    public void updateStatus(@PathVariable("id") Long id, @PathVariable("menuStatus") String menuStatus) {
        UpdateWrapper<SysMenu> updateWrapper = new UpdateWrapper<>();
        updateWrapper.set("menu_status", menuStatus).eq("menu_id", id);
        YUtil.isTrue(!sysMenuService.update(null, updateWrapper), "修改失败，请稍后重试");
    }

    /**
     * @description [是否展开]
     * @author ･ᴗ･
     */
    @PostMapping("/sysMenu/updateSpread/{id}/{isSpread}")
    public void updateSpread(@PathVariable("id") Long id, @PathVariable("isSpread") String isSpread) {
        LambdaUpdateWrapper<SysMenu> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(StringUtils.isNotBlank(isSpread), SysMenu::getIsSpread, isSpread).eq(SysMenu::getMenuId, id);
        YUtil.isTrue(!sysMenuService.update(null, updateWrapper), "修改失败，请稍后重试");
    }

    /**
     * @description [菜单级联下拉框]
     * @author ･ᴗ･
     */
    @GetMapping("/sysMenu/cascaderList")
    public List<CascaderLongBo> cascaderList() {
        return sysMenuService.cascaderList();
    }


    /**
     * @description [生成当前用户所拥有菜单路由]
     * @author ･ᴗ･
     */
    @GetMapping("/sysMenu/listRouters")
    public List<SysMenuBo> generatorRouters() {
        return sysMenuService.generatorRouters();
    }

    /**
     * @description [查询所有正常的路由 AND 展开节点（角色分配菜单权限使用）]
     * @author ･ᴗ･
     */
    @KoiMenuDataScope(menuAlias = "t1")
    @GetMapping("/sysMenu/listMenuNormal")
    public Map<String, Object> listMenuNormal(SysMenuVo sysMenuVo) {
        Map<String, Object> map = new HashMap<>();
        List<SysMenu> menuList = sysMenuService.listMenuNormal(sysMenuVo);
        /* 如果不进行权限数据筛选，则上边一行注释，下边注释解开 */
        // 菜单正常数据
        // LambdaQueryWrapper<SysMenu> wrapper = new LambdaQueryWrapper<>();
        // wrapper.select(SysMenu::getMenuId, SysMenu::getMenuName, SysMenu::getParentId);
        // wrapper.eq(SysMenu::getMenuStatus, KoiConstants.ZERO_STRING);
        // List<SysMenu> menuList = sysMenuService.list(wrapper);
        map.put("menuList", menuList);

        // 菜单是否展开数据
        LambdaQueryWrapper<SysMenu> lambdaWrapper = new LambdaQueryWrapper<>();
        lambdaWrapper.select(SysMenu::getMenuId);
        lambdaWrapper.eq(SysMenu::getIsSpread, KoiConstants.ZERO_STRING);
        lambdaWrapper.eq(SysMenu::getMenuStatus, KoiConstants.ZERO_STRING);
        List<SysMenu> menuSpreadList = sysMenuService.list(lambdaWrapper);
        List<Long> spreadList = menuSpreadList.parallelStream().map(SysMenu::getMenuId).collect(Collectors.toList());
        if (CollectionUtil.isEmpty(spreadList)) {
            spreadList = new ArrayList<>();
        }
        map.put("spreadList", spreadList);
        return map;
    }

    /**
     * @description [根据用户拥有的角色ID查询权限菜单]
     * @author ･ᴗ･
     */
    @GetMapping("/sysMenu/listMenuIdsByRoleId/{roleId}")
    public List<Long> listMenuIdsByRoleId(@PathVariable("roleId") Long roleId) {
        return sysMenuService.listMenuIdsByRoleId(roleId);
    }

    /**
     * @description [保存角色和菜单权限之间的关系]
     * @author ･ᴗ･
     */
    @KoiLog(title = "分配菜单", operType = OperType.AUTH)
    @SaCheckPermission("system:role:menu")
    @PostMapping("/sysMenu/saveRoleMenu/{roleId}/{menuIds}")
    public void saveRoleMenu(@PathVariable("roleId") Long roleId, @PathVariable("menuIds") List<Long> menuIds) {
        sysMenuService.saveRoleMenu(roleId, menuIds);
    }

}
